﻿/*
 *  File: Generation1.cs
 * 
 * 
 *  Author: Aaron C. d. C (AKA Magnus or NinjiHaku)
 *  
 *  Date: 29/07/2013
 *  
 *  License: https://pkmndotnet.codeplex.com/license
 * 
 *  Description: Contains classes and functions to manipulate Generation 1
 *  save files from the Pokemon Games.
 *  
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using PkMnDotNet;

namespace PkMnDotNet
{
    /// <summary>
    /// Contains the memory offsets (addresses) of all the values in the game save file.
    /// </summary>
    public static class Gen1Structs
    {
        /// <summary>
        /// Points to the Player name, and has a length of 8 bytes  (7 chars + terminator).
        /// </summary>
        public static readonly int PlayerNameOffset = 0x2598; //0x2598 8
        /// <summary>
        /// Points to  the Pokedex Owned list, and has a length of 19 bytes.
        /// </summary>
        public static readonly int PokedexOwnedOffset = 0x25A3; //0x25A3 19
        /// <summary>
        /// Points to the Pokedex Seen list, and has a length of 19 bytes.
        /// </summary>
        public static readonly int PokedexSeenOffset = 0x25B6; //0x25B6 19
        /// <summary>
        /// Points to the Item list, and has a length of 42 bytes. The first byte is the item count. Then, Each item is represented by 2 bytes, which are
        /// the quantity, and the Item ID respectively. The last byte is a terminator (0xFF). The max quantity of items is 20.
        /// </summary>
        public static readonly int ItemListOffset = 0x25C9; //0x25C9 42
        /// <summary>
        /// Points to the Player's current money. And has a length of 3 bytes (MSB -> lsb).
        /// </summary>
        public static readonly int MoneyOffset = 0x25F3; //0x25F3 3
        /// <summary>
        /// Points to the rival's name, and has a length of 8 bytes (7 chars + terminator). Don't be rude with him!
        /// </summary>
        public static readonly int RivalNameOffset = 0x25F6; //0x25F6 8
        /// <summary>
        /// Points to the Trainer ID, used to identify the Original Trainer of each pokemon.
        /// Has a length of 2 bytes (MSB -> lsb).
        /// </summary>
        public static readonly int TrainerIDOffset = 0x2605; //0x2605 2
        /// <summary>
        /// A byte that represent the level of friendship with Pikachu, in Yellow version only.
        /// In R/B, this byte is always 0.
        /// </summary>
        public static readonly int PikachuFriendshipOffset = 0x271C;
        /// <summary>
        /// Points to the list of items in the PC, and has a length of 102 bytes.
        /// </summary>
        public static readonly int PCItemListOffset = 0x27E6; //0x27E7 102
        /// <summary>
        /// Points to  the Current Box pointer. It points to the current open box in the Bill's PC.
        /// </summary>
        public static readonly int CurrentBoxOffset = 0x284C; //0x284C 1
        /// <summary>
        /// Points to the time spent. It has 4 individual (1-byte) values representing Hours, Minutes, Seconds, and
        /// frames (1/60 of a Second), in the given order.
        /// </summary>
        public static readonly int TimePlayedOffset = 0x2CEE; //0x2CEE 4
        /// <summary>
        /// Points to  the current Player's party pokemon list.
        /// The first byte represent the number of PkMn in the party. Then, each pokemon species.
        /// There are 7 pokemon in the list (Not 6), the last one is unusable and is always 0xFF.
        /// </summary>
        public static readonly int PokemonListOffset = 0x2F2C; //0x2F2C 404
        /// <summary>
        /// Points to the pokemon box loaded in the memory. The changes made in this box do not affect the
        /// current box unless the data of this box is copied to the current box, and vice versa.
        /// Each Pokemon in the boxes are stored in 33 bytes instead of 44. The missing values are recomputed
        /// after taking the pokemon out of the box.
        /// </summary>
        public static readonly int CurrentBoxPkmnListOffset = 0x30C0; //0x30C0 1122
        /// <summary>
        /// Points to the checksum byte. I recomend using the GetChecksum function included in
        /// the Gen1Functions class to obtain the value for this byte.
        /// </summary>
        public static readonly int ChecksumOffset = 0x3523; //0x3523 1
        /// <summary>
        /// Points to the first box of the game. Each box has a length of 1122 bytes, with a total of
        /// 12 boxes, with up to 20 PkMn per box.
        /// </summary>
        public static readonly int Box1Offset = 0x4000; //0x4000 1122

        /// <summary>
        /// Points to the Original Trainer's name of the first Pokemon. Each one has a lenght of 11 bytes, for 6 pokemon.
        /// Each Pokemon in the boxes are stored in 33 bytes instead of 44. The PPs, the Level and the Maximum HP is recomputed
        /// after taking the pokemon out of the box.
        /// </summary>
        public static readonly int OTPkMnNameOffset = 0x303C;

        /// <summary>
        /// Points to the Pokemon nickname of the first Pokemon. Each one has a length of 11 bytes, for 6 pokemon.
        /// </summary>
        public static readonly int PkMnNameOffset = 0x307E;

        /// <summary>
        /// An integer that represent the total length of one box.
        /// </summary>
        public static readonly int BoxLength = 1122; //4386
        /// <summary>
        /// The amount of boxes in the game.
        /// </summary>
        public static readonly int BoxCount = 12; //1 - 12

        /// <summary>
        /// Contains the alphabet. The first index (0) represents the first character in the game alphabet (0x80).
        /// </summary>
        public static string[] GenIAlph = new string[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", 
        "M","N","O","P","`Q","R","S","T","U","V","W","X","Y","Z","(",")",":",";","[","]","a","b","c","d","e","f","g","h","i","j",
        "k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","□","□","□","□","□","□","□","□","□","□","□","□","□","□",
        "□","□","□","□","□","□","□","□","□","□","□","□","□","□","□","□","□","□","□","□","□","□","□","□","□","Pk","Mn","-","□","□",
        "?","!",".","□","□","□","□","□","□","□","□","×","□","/",",","□","0","1","2","3","4","5","6","7","8","9"};

        /// <summary>
        /// Contains a list of items, order by it's memory index (From 0x00 to 0x53, 84 items).
        /// </summary>
        public static string[] GenIItems = new string[] {
            "Empty",
            "Master Ball",
            "Ultra Ball",
            "Great Ball",
            "Poke Ball",
            "Town Map",
            "Bycicle",
            "????? (Dummy/glitch item)",
            "Safari Ball",
            "Pokedex",
            "Moon Stone",
            "Antidote",
            "Burn Heal",
            "Ice Heal",
            "Awakening",
            "Paralyz Heal",
            "Full Restore",
            "Max Potion",
            "Hyper Potion",
            "Super Potion",
            "Potion",
            "Boulder Badge",
            "Cascade Badge",
            "Thunder Badge",
            "Rainbow Badge",
            "Soul Badge",
            "Marsh Badge",
            "Volcano Badge",
            "Earth Badge",
            "Escape Rope",
            "Repel",
            "Old Amber",
            "Fire Stone",
            "Thunder Stone",
            "Water Stone",
            "HP Up",
            "Protein",
            "Iron",
            "Carbos",
            "Calcium",
            "Rare Candy",
            "Dome Fossil",
            "Helix Fossil",
            "Secret Key",
            "????? (Dummy/Glitch item)",
            "Bike Voucher",
            "X Accuracy",
            "Leaf Stone",
            "Card Key",
            "Nugget",
            "PP Up",
            "Poké Doll",
            "Full Heal",
            "Revive",
            "Max Revive",
            "Guard Spec.",
            "Super Repel",
            "Max Repel",
            "Dire Hit",
            "Coin",
            "Fresh Water",
            "Soda Pop",
            "Lemonade",
            "S.S Ticket",
            "Gold Theet",
            "X Attack",
            "X Defend",
            "X Speed",
            "X Special",
            "Coin Case",
            "Oak's Parcel",
            "Itemfinder",
            "Silph Scope",
            "Poke Flute",
            "Lift Key",
            "Exp. All",
            "Old Rod",
            "Good Rod",
            "Super Rod",
            "PP Up",
            "Ether",
            "Max Ether",
            "Elixir (Elixer)",
            "Max Elixir"
        };

        /// <summary>
        /// Contains a list of the Hidden Machines, ordered by it's Item memory ID. Starting from 0xC4 (196) to 0xC8 (200), with a total of 5 HM.
        /// </summary>
        public static string[] GenIHM = new string[] {
            "HM01 Cut",
            "HM02 Fly",
            "HM03 Surf",
            "HM04 Strength",
            "HM05 Flash"
        };

        /// <summary>
        /// The ID of the first Technical Machine. From this TM (0xC9), to TM55 (0x255), everything is a TM.
        /// </summary>
        public static readonly int TM01 = 0xC9;

        /// <summary>
        /// The ID of the last Technical Machine. From this TM (0xFF), to TM01 (0xC9), everything is a TM.
        /// </summary>
        public static readonly int TM55 = 0xFF;

        /// <summary>
        /// Contains a list of all Generation 1 moves, ordered by it's ID (According to the Bulbapedia)
        /// </summary>
        public static string[] GenIMoves = new string[] {
            "Pound",
            "Karate Chop",
            "Double Slap",
            "Comet Punch",
            "Mega Punch",
            "Pay Day",
            "Fire Punch",
            "Ice Punch",
            "Thunder Punch",
            "Scratch",
            "Vice Grip",
            "Guillotine",
            "Razord Wind",
            "Swords Dance",
            "Cut",
            "Gust",
            "Wing Attack",
            "Whirldwind",
            "Fly",
            "Bind",
            "Slam",
            "Vine Whip",
            "Stomp",
            "Double Kick",
            "Mega Kick",
            "Jump Kick",
            "Rolling Kick",
            "Sand Attack",
            "Head butt",
            "Horn Attack",
            "Fury Attack",
            "Horn Drill",
            "Tackle",
            "Body Slam",
            "Wrap",
            "Take Down",
            "Thrash",
            "Double-Edge",
            "Tail Whip",
            "Poison Sting",
            "Twineedle",
            "Pin Missile",
            "Leer",
            "Bite",
            "Growl",
            "Roar",
            "Sing",
            "Supersonic",
            "SonicBoom",
            "Disable",
            "Acid",
            "Ember",
            "Flamethrower",
            "Mist",
            "Water Gun",
            "Hydro Pump",
            "Surf",
            "Ice Beam",
            "Blizzard",
            "Psybeam",
            "Bubble Beam",
            "Aurora Beam",
            "Hyper Beam",
            "Peck",
            "Drill Peck",
            "Submission",
            "Low Kick",
            "Counter",
            "Seismic Toss",
            "Strength",
            "Absorb",
            "Mega Drain",
            "Leech Seed",
            "Growth",
            "Razor Leaf",
            "Solar Beam",
            "Poison Powder",
            "Stun Spore",
            "Sleep Powder",
            "Petal Dance",
            "String Shot",
            "Dragon Rage",
            "Fire Spin",
            "ThunderShock",
            "ThunderBolt",
            "ThunderWave",
            "Thunder",
            "Rock Throw",
            "Earthquake",
            "Fissure",
            "Dig",
            "Toxic",
            "Confussion",
            "Psychic",
            "Hypnosis",
            "Meditate",
            "Agility",
            "Quick Attack",
            "Rage",
            "Teleport",
            "Night Shade",
            "Mimic",
            "Screech",
            "Double Team",
            "Recover",
            "Harden",
            "Minimize",
            "Smoke Screen",
            "Confuse Ray",
            "Withdraw",
            "Defense Curl",
            "Barrier",
            "Light Screen",
            "Haze",
            "Reflect",
            "Focus Energy",
            "Bide",
            "Metronome",
            "Mirror Move",
            "Self Destruct",
            "Egg Bomb",
            "Lick",
            "Smog",
            "Sludge",
            "Bone Club",
            "Fire Blast",
            "Waterfall",
            "Clamp",
            "Swift",
            "Skull Bash",
            "Spike Cannon",
            "Constrict",
            "Amnesia",
            "Kinesis",
            "Softboiled",
            "Hi Jump Kick",
            "Glare",
            "Dream Eater",
            "Poison Gas",
            "Barrage",
            "Leech Life",
            "Lovely Kiss",
            "Sky Attack",
            "Transform",
            "Bubble",
            "Dizzy Punch",
            "Spore",
            "Flash",
            "Psywave",
            "Splash",
            "Acid Armor",
            "Crabhammer",
            "Explosion",
            "Fury Swipes",
            "Bonemerang",
            "Rest",
            "Rock Slide",
            "Hyper Fang",
            "Sharpen",
            "Converion",
            "Tri Attack",
            "Super Fang",
            "Slash",
            "Substitute",
            "Struggle"
        };

        /// <summary>
        /// A list of Generation 1 Types, ordered by it's memory ID.
        /// </summary>
        public static string[] GenITypes = new string[] {
            "Normal",
            "Fighting",
            "Poison",
            "Ground",
            "Rock",
            "Bug",
            "Ghost",
            "Unused/Glitch",
            "Unused/Glitch",
            "Unused/Glitch",
            "Unused/Glitch",
            "Unused/Glitch",
            "Unused/Glitch",
            "Unused/Glitch",
            "Unused/Glitch",
            "Unused/Glitch",
            "Unused/Glitch",
            "Unused/Glitch",
            "Fire",
            "Water",
            "Grass",
            "Electric",
            "Psychic",
            "Ice",
            "Dragon"
        };

        /// <summary>
        /// A list containing all the Pokemon in the game, including missing numbers (MissingNo) and glitches. Shorted by it's memory ID value (from 0x00 to 0xFF).
        /// </summary>
        public static string[] GenIList = new string[256] { "MissingNo (Original)",
            "Rhydon",
        "Kangaskhan",
        "Nidoran M",
        "Clefairy",
        "Spearow",
        "Voltorb",
        "Nidoking",
        "Slowbro",
        "Ivysaur",
        "Exeggutor",
        "Lickitung",
        "Exeggcute",
        "Grimer",
        "Gengar",
        "Nidoran F",
        "Nidoqueen",
        "Cubone",
        "Rhyhorn",
        "Lapras",
        "Arcanine",
        "Mew",
        "Gyarados",
        "Shellder",
        "Tentacool",
        "Gastly",
        "Scyther",
        "Staryu",
        "Blastoise",
        "Pinsir",
        "Tangela",
        "Missingno",
        "Missingno",
        "Growlithe",
        "Onix",
        "Fearow",
        "Pidgey",
        "Slowpoke",
        "Kadabra",
        "Graveler",
        "Chansey",
        "Machoke",
        "Mr. Mime",
        "Hitmonlee",
        "Hitmonchan",
        "Arbok",
        "Parasect",
        "Psyduck",
        "Drowzee",
        "Golem",
        "Missingno",
        "Magmar",
        "Missingno",
        "Electabuzz",
        "Magneton",
        "Koffing",
        "Missingno",
        "Mankey",
        "Seel",
        "Diglett",
        "Tauros",
        "Missingno",
        "Missingno",
        "Missingno",
        "Farfetch'd",
        "Venonat",
        "Dragonite",
        "Missingno",
        "Missingno",
        "Missingno",
        "Doduo",
        "Poliwag",
        "Jynx",
        "Moltres",
        "Articuno",
        "Zapdos",
        "Ditto",
        "Meowth",
        "Krabby",
        "Missingno",
        "Missingno",
        "Missingno",
        "Vulpix",
        "Ninetales",
        "Pikachu",
        "Raichu",
        "Missingno",
        "Missingno",
        "Dratini",
        "Dragonair",
        "Kabuto",
        "Kabutops",
        "Horsea",
        "Seadra",
        "Missingno",
        "Missingno",
        "Sandshrew",
        "Sandlash",
        "Omanyte",
        "Omastar",
        "Jigglypuff",
        "Wigglytuff",
        "Eevee",
        "Flareon",
        "Jolteon",
        "Vaporeon",
        "Machop",
        "Zubat",
        "Ekans",
        "Paras",
        "Poliwhirl",
        "Poliwrath",
        "Weedle",
        "Kakuna",
        "Beedrill",
        "Missingno",
        "Dodrio",
        "Primeape",
        "Dugtrio",
        "Venomoth",
        "Dewgong",
        "Missingno",
        "Missingno",
        "Caterpie",
        "Metapod",
        "Butterfree",
        "Machamp",
        "Missingno",
        "Golduck",
        "Hypno",
        "Golbat",
        "Mewtwo",
        "Snorlax",
        "Magikarp",
        "Missingno",
        "Missingno",
        "Muk",
        "Missingno",
        "Kingler",
        "Cloyster",
        "Missingno",
        "Electrode",
        "Clefable",
        "Weezing",
        "Persian",
        "Marowak",
        "Missingno",
        "Haunter",
        "Abra",
        "Alakazam",
        "Pidgeotto",
        "Pidgeot",
        "Starmie",
        "Bulbasaur",
        "Venusaur",
        "Tentacruel",
        "Missingno",
        "Goldeen",
        "Seaking",
        "Missingno",
        "Missingno",
        "Missingno",
        "Missingno",
        "Ponyta",
        "Rapidash",
        "Rattata",
        "Raticate",
        "Nidorino",
        "Nidorina",
        "Geodude",
        "Porygon",
        "Aerodactil",
        "Missingno",
        "Magnemite",
        "Missingno",
        "Missingno",
        "Charmander",
        "Squirtle",
        "Charmeleon",
        "Wartortle",
        "Charizard",
        "Missingno",
        "Missingno",
        "Missingno",
        "Missingno",
        "Oddish",
        "Gloom",
        "Vileplume",
        "Bellsprout",
        "Weepinbell",
        "Victreebel",
        "▶ A/4 4",
        "a/4\"4Hy ",
        "ゥ (C1)/♀ . ",
        " 	ゥ .4/PPkMnp' ' ",
        "h POKé/ゥ ( Z4 ",
        "PokéWTrainer/X ゥ- xゥ, ",
        "PkMn (C5)/4. .",
        " 	ゥL ゥM 4/7g (",
        " 	♀Pゥ ゥゥT/u ",
        " 	ゥU?/g g ",
        "◣ゥ 8/ァ / g J 1 ",
        " 	PC4SH/Glitch (CA) ",
        " 	P/. pゥ ",
        " 	PkMn ◣ n/.8 ",
        "Trainer/ゥ. B ",
        "▼ W G d/PKMN pゥぁ ゥぇ ",
        "OPKMN4X/4, ゥァ ",
        " 	PKMN PKMN T/ゥ' ",
        " 	4B 8 4 8/B ァ h ",
        " 	ゥ '/PKMN ? A ",
        " 	M p'u ゥ/ゥゥ) ",
        "Aゥ G/ゥ ",
        "Pゥ ゥ ゥ/'ゥ. ",
        " 	4h/PKMN pゥぁ ゥぇ",
        "B ",
        "PkMnaPkMnゥ ♂ fPkMnk/PkMn ",
        " 	PKMNRPKMN \"/ゥ ",
        "B (DA)/] ",
        " 	Glitch (DB)/ゥ'B ",
        "Glitch (DC)/PKMN ",
        " 	7PKMN 'v/4, ゥァ ",
        " 	-PkMn/8",
        " 	.PKMN/p ID ",
        " 	/PkMn ▼PkMn/8 P ァ ",
        " 	'v/'r 'r 4 ",
        " 	……/(h4to89",
        " 	ゥ (E3)/4HI 89 4to ",
        "Glitch (E4)/8B 4 8 ",
        " 	C/Z ゥ ",
        " 	- -/9 ",
        "Pゥ 4$/ゥHIゥ. ",
        "X:LC/4(h4hi?$ ",
        "c/4HI? ",
        " 	A (EA)/'r ゥ ",
        " 	Glitch (EB)/$ Pゥ. 4( ",
        " 	Glitch (EC)/?/ ",
        " 	hゥ/4(h4? ",
        " 	.g/ゥ► ゥ▼ ゥ ",
        " 	ゥ$'M/h 4Pゥ ゥ... ",
        " 	. ゥ ( .I' ./ゥ$ ",
        " 	94/' B' ゥ ",
        " 	ゥ l (F2)/ゥ ゥェ ゥ ▷ ",
        " 	ゥ l (F3)/ゥ $ A ",
        "ゥ$ (F4)/♂ p ゥ ",
        " 	Glitch (F5)/▼ pゥ",
        " 	G'Mp/ゥ $ A (F6) ",
        "'Ng'Mp/PKMN",
        " 	'Ng ゥ$/ゥ 4ぁ 4",
        "94 h/$ ",
        "Glitch (FA)/ゥ▾ ゥ♂ ",
        " 	'M'Ng/F q,",
        "O/$ 4Mn ",
        "$6/ 'r .4- ",
        "'M (3)/ 4 4, ",
        " 	'M (FF)/Q◣ ",};
    }

    /// <summary>
    /// Class that represent a Pokemon in the game. Can be instantiated. Each parameter can be
    /// edited individually.
    /// </summary>
    public class Gen1Pokemon
    {
        /// <summary>
        /// Byte that represent this PkMn Specie (Bulbasaur, Ivysaur, Venusaur...). It is not the Pokedex entry number, but the PkMn byte in the memory (IE: 0x01 = Rhydon).
        /// See the Bulbapedia for more info about each PkMn byte for the first generation.
        /// </summary>
        public byte Species;
        /// <summary>
        /// Byte that represent the current HP of the PkMn. M = Major byte, m = minor byte.
        /// If this byte is greater than the Maximum HP, the life bar will glitch.
        /// </summary>
        public byte HPM, HPm; //HPm = LSB, HPM = MSB
        /// <summary>
        /// The level of the pokemon, that is shown when stored in the PC.
        /// </summary>
        public byte LevelPC; //As viewed on the PC
        /// <summary>
        /// Current status of the PkMn. 0x00 is OK.
        /// 0x08 is Poisoned. 0x10 is Burned. 0x20 is Frozen. And 0x40, Paralyzed.
        /// </summary>
        public byte Status;
        /// <summary>
        /// The first type of the pokemon. From 0x00 (Normal), to 0x1A (Dragon).
        /// </summary>
        public byte Type1;
        /// <summary>
        /// The second type of the pokemon. From 0x00 (Normal), to 0x1A (Dragon).
        /// </summary>
        public byte Type2;
        /// <summary>
        /// The catch rate of the Pokemon. This does not affect the pokemon, since it
        /// is already catched.
        /// </summary>
        public byte CRate;
        /// <summary>
        /// Byte that represent the first move of the PkMn.
        /// </summary>
        public byte Move1;
        /// <summary>
        /// Byte that represent the second move of the PkMn.
        /// </summary>
        public byte Move2;
        /// <summary>
        /// Byte that represent the third move of the PkMn.
        /// </summary>
        public byte Move3;
        /// <summary>
        /// Byte that represent the fourth move of the PkMn.
        /// </summary>
        public byte Move4;
        /// <summary>
        /// 2 Bytes, being A the major, and B the minor, that represent the Trainer's ID.
        /// </summary>
        public byte TIDA, TIDB; //A = MSB, B = lsb
        /// <summary>
        /// 3 Bytes, being A the major, and C the minor, that represent the PkMn Experience.
        /// It also represent the level of the pokemon, when it level up. Should not be
        /// greater than about 1,250,000.
        /// </summary>
        public byte EXPA, EXPB, EXPC;
        /// <summary>
        /// 2 Bytes, being A the major, and B the minor, that represent the HP Individual Values
        /// </summary>
        public byte HPVA, HPVB;
        /// <summary>
        /// 2 Bytes, being A the major, and B the minor, that represent the Attack Individual Values
        /// </summary>
        public byte ATTVA, ATTVB;
        /// <summary>
        /// 2 Bytes, being A the major, and B the minor, that represent the Defense Individual values.
        /// </summary>
        public byte DEFVA, DEFVB;
        /// <summary>
        /// 2 Bytes, being A the major, and B the minor, that represent the speed individual values.
        /// </summary>
        public byte SPDVA, SPDVB;
        /// <summary>
        /// 2 Bytes, being A the major, and B the minor, that represent the special individual values.
        /// </summary>
        public byte SPEVA, SPEVB;
        /// <summary>
        /// 2 Bytes, being A the major, and B the minor, that represent the individual values.
        /// </summary>
        public byte IVA, IVB;
        /// <summary>
        /// The PP of the first move.
        /// </summary>
        public byte PP1;
        /// <summary>
        /// The PP of the second move.
        /// </summary>
        public byte PP2;
        /// <summary>
        /// The PP of the third move.
        /// </summary>
        public byte PP3;
        /// <summary>
        /// The PP of the fourth move.
        /// </summary>
        public byte PP4;
        /// <summary>
        /// The level of the current Pokemon. Should match the EXP. Otherwishe,
        /// the level will be recomputed when it level up.
        /// </summary>
        public byte Level;
        /// <summary>
        /// 2 Bytes, being A the major, and B the minor, that represent the Maximum HP.
        /// If it is lesser than the current HP, the life bar glitches.
        /// </summary>
        public byte MaxHPA, MaxHPB;
        /// <summary>
        /// 2 Bytes, being A the major, and B the minor, that represent the Attack value.
        /// </summary>
        public byte ATTA, ATTB;
        /// <summary>
        /// 2 Bytes, being A the major, and B the minor, that represent the Deffense value.
        /// </summary>
        public byte DEFA, DEFB;
        /// <summary>
        /// 2 Bytes, being A the major, and B the minor, that represent the Speed value.
        /// </summary>
        public byte SPDA, SPDB;
        /// <summary>
        /// 2 Bytes, being A the major, and B the minor, that represent the Special value.
        /// </summary>
        public byte SPEA, SPEB;
        /// <summary>
        /// A string of 11 bytes representing the Original Trainer's name.
        /// </summary>
        public byte[] OTName = new byte[10];
        /// <summary>
        /// A string of 11 bytes representing the Pokemon's nickname.
        /// </summary>
        public byte[] PkMnName = new byte[10];

        /// <summary>
        /// Class that represent a Pokemon in the game. Can be instantiated. Each parameter can be
        /// edited individually.
        /// </summary>
        public Gen1Pokemon()
        {
            Species = 0x01;
            HPM = 0x00; HPm = 0x1E;
            LevelPC = Level = 0x05;
            Status = 0x00;
            Type1 = 0x04; Type2 = 0x05;
            CRate = 0x3C;
            Move1 = 0x1E; Move2 = 0x27;
            Move3 = 0x17; Move4 = 0x1F;
            TIDA = 0x00; TIDB = 0x00;
            EXPC = 0xFF; EXPB = 0x00; EXPA = 0x00;
            ATTA = 0x00; ATTB = 0x55;
            DEFA = 0x00; DEFB = 120;
            SPDA = 0; SPDB = 45;
            SPEA = 0; SPEB = 40;
            ATTVA = 0x00; ATTVB = 0x02;
            DEFVA = 0x00; DEFVB = 0;
            SPDVA = 0; SPDVB = 0;
            SPEVA = 0; SPEVB = 0;
            HPVA = 0; HPVB = 0;
            IVA = 0x00; IVB = 0x50;
            PP1 = 20; PP2 = 20;
            PP3 = 20; PP4 = 20;
            Level = 5;
            MaxHPA = 0x00; MaxHPB = 30;
            OTName = new byte[10] { 0x87, 0x80, 0x82, 0x8A, 0x84, 0x91, 0x50, 0x00, 0x00, 0x00 };
            PkMnName = new byte[10] { 0x87, 0x80, 0x82, 0x8A, 0x84, 0x83, 0x50, 0x00, 0x00, 0x00 };
        }

        /// <summary>
        /// Loads a Pokemon from a stream of 44 exact bytes. Returns false if it fails.
        /// </summary>
        /// <param name="Data">The bytes containing the Pokemon data. Must be 44 bytes.</param>
        /// <returns>Return true if success.</returns>
        public bool LoadFromBytes(byte[] Data)
        {
            if (Data.Length != 44)
                return false;

            Species = Data[0];
            HPM = Data[1]; HPm = Data[2];
            LevelPC = Data[33];
            Status = Data[4];
            Type1 = Data[5]; Type2 = Data[6];
            CRate = Data[7];
            Move1 = Data[8]; Move2 = Data[9];
            Move3 = Data[10]; Move4 = Data[11];
            TIDA = Data[12]; TIDB = Data[13];
            EXPC = Data[16]; EXPB = Data[15]; EXPA = Data[14];
            ATTA = Data[36]; ATTB = Data[37];
            DEFA = Data[38]; DEFB = Data[39];
            SPDA = Data[40]; SPDB = Data[41];
            SPEA = Data[42]; SPEB = Data[43];
            ATTVA = Data[19]; ATTVB = Data[20];
            DEFVA = Data[21]; DEFVB = Data[22];
            SPDVA = Data[23]; SPDVB = Data[24];
            SPEVA = Data[25]; SPEVB = Data[26];
            HPVA = Data[17]; HPVB = Data[18];
            IVA = Data[27]; IVB = Data[28];
            PP1 = Data[29]; PP2 = Data[30];
            PP3 = Data[31]; PP4 = Data[32];
            Level = Data[33];
            MaxHPA = Data[34]; MaxHPB = Data[35];
            return true;
        }

        /// <summary>
        /// Loads a pokemon from a stream of 33 exact bytes, representing a PkMn in a box.
        /// </summary>
        /// <param name="Data">The bytes containing the Pokemon data. Must be 33 bytes.</param>
        /// <returns>Returns true if success.</returns>
        public bool LoadFromPCBytes(byte[] Data)
        {
            if (Data.Length != 33)
                return false;

            Species = Data[0];
            HPM = Data[1]; HPm = Data[2];
            LevelPC = Data[33];
            Status = Data[4];
            Type1 = Data[5]; Type2 = Data[6];
            CRate = Data[7];
            Move1 = Data[8]; Move2 = Data[9];
            Move3 = Data[10]; Move4 = Data[11];
            TIDA = Data[12]; TIDB = Data[13];
            EXPC = Data[16]; EXPB = Data[15]; EXPA = Data[14];
            ATTVA = Data[19]; ATTVB = Data[20];
            DEFVA = Data[21]; DEFVB = Data[22];
            SPDVA = Data[23]; SPDVB = Data[24];
            SPEVA = Data[25]; SPEVB = Data[26];
            HPVA = Data[17]; HPVB = Data[18];
            IVA = Data[27]; IVB = Data[28];
            PP1 = Data[29]; PP2 = Data[30];
            PP3 = Data[31]; PP4 = Data[32];
            return true;
        }

        /// <summary>
        /// Loads a pokemon from the Player party, from the save file.
        /// </summary>
        /// <param name="fs">A file stream that points to the save file.</param>
        /// <param name="PartyPosition">The index of the pokemon, in the Player's party, that must be loaded.</param>
        /// <returns>Returns true if success.</returns>
        public bool LoadFromSaveFile(FileStream fs, byte PartyPosition)
        {
            if (PartyPosition < 1 || PartyPosition > 6)
                return false;

            byte[] Data = new byte[44];

            //Locate the first byte of the Pokemon.
            fs.Seek(Gen1Structs.PokemonListOffset + 8 + (44 * (PartyPosition - 1)), SeekOrigin.Begin);

            //Read each byte from the Pokemon.
            for (int x = 0; x < Data.Length; x++)
            {
                Data[x] = (byte)fs.ReadByte();
            }

            //Load the pokemon into the instance. If it fails, return.
            if (!LoadFromBytes(Data))
                return false;

            //Now seek for the Original Trainer name.
            fs.Seek(0x303C + (11 * (PartyPosition - 1)), SeekOrigin.Begin);

            //Read it.
            for (int y = 0; y < 10; y++)
            {
                OTName[y] = (byte)fs.ReadByte();
            }

            //And the same for the pokemon nickname.
            fs.Seek(0x307E + (11 * (PartyPosition - 1)), SeekOrigin.Begin);

            for (int y = 0; y < 10; y++)
            {
                PkMnName[y] = (byte)fs.ReadByte();
            }

            return true;
        }

        /// <summary>
        /// Return an array of bytes containing the Pokemon information.
        /// </summary>
        /// <returns>An array of bytes containig the PkMn data.</returns>
        public byte[] ReturnBytes()
        {
            byte[] DataBytes = new byte[44];

            DataBytes[0] = Species; //Species
            DataBytes[1] = HPM; DataBytes[2] = HPm; //HP
            DataBytes[3] = Level; //Level in the PC
            DataBytes[4] = Status;//Status
            DataBytes[5] = Type1; DataBytes[6] = Type2; //Type
            DataBytes[7] = CRate; //Catch rate
            DataBytes[8] = Move1; DataBytes[9] = Move2; //Moves 1 2
            DataBytes[10] = Move3; DataBytes[11] = Move4; //Moves 3 4
            DataBytes[12] = TIDA; DataBytes[13] = TIDB; //Trainer ID
            DataBytes[14] = EXPA; DataBytes[15] = EXPB; DataBytes[16] = EXPC; //EXP
            DataBytes[17] = HPVA; DataBytes[18] = HPVB; //HP EV
            DataBytes[19] = ATTVA; DataBytes[20] = ATTVB; //ATT IV
            DataBytes[21] = DEFVA; DataBytes[22] = DEFVB; //DEF IV
            DataBytes[23] = SPDVA; DataBytes[24] = SPDVB; //SPEED IV
            DataBytes[25] = SPEVA; DataBytes[26] = SPEVB; //SPECIAL IV
            DataBytes[27] = IVA; DataBytes[28] = IVB; //IV DATA
            DataBytes[29] = PP1; DataBytes[30] = PP2; //PP 1 2
            DataBytes[31] = PP3; DataBytes[32] = PP4; //PP 3 4
            DataBytes[33] = Level; //LEVEL
            DataBytes[34] = MaxHPA; DataBytes[35] = MaxHPB; //MAX HP
            DataBytes[36] = ATTA; DataBytes[37] = ATTB; //ATTACK
            DataBytes[38] = DEFA; DataBytes[39] = DEFB; //DEFENSE
            DataBytes[40] = SPDA; DataBytes[41] = SPDB; //SPEED
            DataBytes[42] = SPEA; DataBytes[43] = SPEB; //SPECIAL

            return DataBytes;
        }

        /// <summary>
        /// Return a byte array of 33 exact bytes containing the Pokemon information.
        /// </summary>
        /// <returns>Return a byte array of 33 exact bytes containing the Pokemon information.</returns>
        public byte[] ReturnPCBytes()
        {
            byte[] DataBytes = new byte[33];

            DataBytes[0] = Species; //Species
            DataBytes[1] = HPM; DataBytes[2] = HPm; //HP
            if (Level != 0 || Level <= 100)
                DataBytes[3] = Level; //Level in the PC
            else
                DataBytes[3] = LevelPC; //Level in the PC
            DataBytes[4] = Status;//Status
            DataBytes[5] = Type1; DataBytes[6] = Type2; //Type
            DataBytes[7] = CRate; //Catch rate
            DataBytes[8] = Move1; DataBytes[9] = Move2; //Moves 1 2
            DataBytes[10] = Move3; DataBytes[11] = Move4; //Moves 3 4
            DataBytes[12] = TIDA; DataBytes[13] = TIDB; //Trainer ID
            DataBytes[14] = EXPA; DataBytes[15] = EXPB; DataBytes[16] = EXPC; //EXP
            DataBytes[17] = HPVA; DataBytes[18] = HPVB; //HP EV
            DataBytes[19] = ATTVA; DataBytes[20] = ATTVB; //ATT IV
            DataBytes[21] = DEFVA; DataBytes[22] = DEFVB; //DEF IV
            DataBytes[23] = SPDVA; DataBytes[24] = SPDVB; //SPEED IV
            DataBytes[25] = SPEVA; DataBytes[26] = SPEVB; //SPECIAL IV
            DataBytes[27] = IVA; DataBytes[28] = IVB; //IV DATA
            DataBytes[29] = PP1; DataBytes[30] = PP2; //PP 1 2
            DataBytes[31] = PP3; DataBytes[32] = PP4; //PP 3 4
            return DataBytes;
        }

        /// <summary>
        /// Return the name of a specified move in a string.
        /// </summary>
        /// <param name="MoveIndex">The index of the move</param>
        /// <returns>The name of the move</returns>
        public string GetMoveName(byte MoveIndex)
        {
            return Gen1Structs.GenIMoves[MoveIndex];
        }
    }

    /// <summary>
    /// Class that represent an in-game item. Can be instantiated.
    /// </summary>
    public class Item
    {
        /// <summary>
        /// The ID of the item.
        /// </summary>
       public byte ID;
        /// <summary>
        /// The item count in the inventory.
        /// </summary>
       public byte Count;

       /// <summary>
       /// Class that represent an in-game item. Can be instantiated.
       /// </summary>
        public Item()
        {
            ID = 0x0;
            Count = 0x0;
        }

        /// <summary>
        /// Class that represent an in-game item. Can be instantiated.
        /// </summary>
        /// <param name="_Count">The quantity of items.</param>
        /// <param name="_ID">The game ID of the item</param>
        public Item(byte _Count, byte _ID)
        {
            ID = _ID;
            Count = _Count;
        }

        /// <summary>
        /// Returns an array of 2 bytes representing the Item structure.
        /// </summary>
        /// <returns>An array of 2 bytes representing the Item structure.</returns>
        public byte[] ReturnDataArray()
        {
            byte[] ItemData = new byte[2];
            ItemData[0] = ID; ItemData[1] = Count;
            return ItemData;
        }

        /// <summary>
        /// Returns the name of the item, in a string.
        /// </summary>
        /// <returns>The name of the item, in a string.</returns>
        public string GetItemName()
        {
            if (this.ID < 84)
                return Gen1Structs.GenIItems[this.ID];
            else if (this.ID >= 196 && this.ID <= 200)
                return Gen1Structs.GenIHM[this.ID - 196];
            else if (this.ID >= 0xC9)
                return "TM " + (55-(255 - this.ID)).ToString();

            return "Unidentified";
        }
    }

    /// <summary>
    /// Class that can contain the inventory of a save file. Can be instantiated.
    /// </summary>
    public class Inventory
    {
        /// <summary>
        /// The number of items in the list
        /// </summary>
        public byte ItemCount;
        
        //Basically, an inventory is just an Item list. So we make an Item array called List.

        /// <summary>
        /// The list of Items
        /// </summary>
        public Item[] List = new Item[1];

        /// <summary>
        /// Class that can contain the inventory of a save file.
        /// </summary>
        public Inventory()
        {
            ItemCount = 0;
            List[0].ID = 0x0; List[0].Count = 0x0;
        }

        /// <summary>
        /// Class that can contain the inventory of a save file.
        /// </summary>
        /// <param name="fs">A file stream that points to a save file</param>
        /// <param name="Source">If set to 0, it will load the bytes of the inventory.
        /// If set to 1 or above, it will load the bytes of the PC inventory</param>
        public Inventory(FileStream fs, byte Source)
        {
            byte[] itembytes = new byte[2];
            
            //Depending on the selected source, we create a player
            //inventory list (20 item), or a PC inventory (50)
            if(Source < 1)
                List = new Item[BitTools.ReadByte(Gen1Structs.ItemListOffset, fs)]; //The player inventory
            else
                List = new Item[BitTools.ReadByte(Gen1Structs.PCItemListOffset, fs)]; //The PC inventory.
            for (int x = 0; x < List.Length; x++)
            {
                //Pretty much the same. We load an item from one source, or another.
                if (Source < 1)
                    itembytes = BitTools.ReadByte(Gen1Structs.ItemListOffset + 1 + (2 * x), 2, fs);
                else
                    itembytes = BitTools.ReadByte(Gen1Structs.PCItemListOffset + 1 + (2 * x), 2, fs);
                    
                //We add the loaded item to the inventory.
                List[x] = new Item(itembytes[1], itembytes[0]);
            }
        }

        /// <summary>
        /// Class that can contain the inventory of a save file.
        /// </summary>
        /// <param name="InventoryData">An array of bytes that contains the data of the inventory.
        /// Must be 42 bytes of length, and can be up to 102 bytes long (PC Items).</param>
        public Inventory(byte[] InventoryData)
        {
            if (InventoryData.Length < 42 || InventoryData.Length > 102)
            {
                //If the data array has a wrong length, we just return 0x0
                ItemCount = 0;
                List[0].ID = 0x0; List[0].Count = 0x0;
                return;
            }
            int cnt = 1;

            //Create an inventory of 2 times the length of our data array (Each item has 2 bytes).

            List = new Item[InventoryData.Length >> 1];

            //Parse each 2 bytes into an item in the inventory.

            for (int x = 0; x < List.Length; x++)
            {
                List[x].Count = InventoryData[cnt+1]; List[x].ID = InventoryData[cnt];
                cnt += 2;
                if (cnt > InventoryData.Length) //If we are out of items, stop.
                    break;
            }
        }

        /// <summary>
        /// Saves the inventory in a SaveFile, and rewrites the file Checksum
        /// </summary>
        /// <param name="Source">Set this to 0 to save the Player inventory, or to 1 or greater
        /// to save a PC inventory.</param>
        /// <param name="fs">The filestream that points to the save file.</param>
        /// <returns>Returns TRUE if succeed.</returns>
        public bool SaveInventory(byte Source, FileStream fs)
        {
            //Check if the parameters are correct
            if (Source < 1 && List.Length > 20)
                return false;
            if (Source >= 1 && List.Length > 50)
                return false;

            //Depending on the source, we write the inventory length in one place, or another.
            if (Source < 1)
                BitTools.WriteByte(Gen1Structs.ItemListOffset, (byte)List.Length, fs);
            else
                BitTools.WriteByte(Gen1Structs.PCItemListOffset, (byte)List.Length, fs);

            //Store each item in the save file.
            if (Source < 1)
                for (int x = 0; x < List.Length; x++)
                    BitTools.WriteByte(Gen1Structs.ItemListOffset + 1, List[x].ReturnDataArray(), fs);
            else
                for (int x = 0; x < List.Length; x++)
                    BitTools.WriteByte(Gen1Structs.PCItemListOffset + 1, List[x].ReturnDataArray(), fs);

            //Recompute and write the checksum of the file.
            Gen1Functions.RewriteChecksum(fs.Name);
            return true;
        }
    }

    /// <summary>
    /// Functions relative to the Generation 1 Pokemon games
    /// </summary>
    public static class Gen1Functions
    {
        private static FileStream PkMnFs;
        private static bool IsLoaded = false;

        /// <summary>
        /// Returns the current FileStream used by the class.
        /// If the current FileStream of this class is not in use, it will return NULL.
        /// </summary>
        /// <returns>The FileStream used by this class</returns>
        public static FileStream GetFileStream()
        {
            if (IsLoaded)
                return PkMnFs;
            return null;
        }

        /// <summary>
        /// A Boolean flag that indicate if the File Stream used by this class is loaded or not.
        /// </summary>
        public static bool IsFileStreamLoaded
        {
            get { return IsLoaded; }
        }

        /// <summary>
        /// Convert a stream of raw byte characters, into a text string.
        /// </summary>
        /// <param name="RawText">The stream of bytes containing the characters.</param>
        /// <returns>A string with the processed text.</returns>
        public static string ConvertTextToString(byte[] RawText)
        {
            string Text = "";
            for (int x = 0; x < RawText.Length; x++)
            {

                if (RawText[x] == 0x50) //Terminator
                    break;
                if (RawText[x] == 0x7F) //Space
                {
                    Text += " ";
                    continue;
                }

                if (RawText[x] <= 0x7F || (RawText[x] >= 0xBA && RawText[x] <= 0xE0) || (RawText[x] >= 0xE4 && RawText[x] <= 0xE5) || (RawText[x] >= 0xE9 && RawText[x] <= 0xF0) || RawText[x] == 0xF3 || RawText[x] == 0xF5)
                    continue; //Skip any unused character

                //Add the character to the string.
                Text += Gen1Structs.GenIAlph[RawText[x] - 0x80];
            }

            return Text;
        }

        /// <summary>
        /// DEPRECATED. Used for debug purposes only. Shall not be used, unless you get corrupted save files.
        /// </summary>
        /// <param name="SaveFilePath">The path to the save file.</param>
        public static void DebugChecksum(string SaveFilePath)
        {
            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            PkMnFs.Seek(Gen1Structs.ChecksumOffset, SeekOrigin.Begin);
            MessageBox.Show(PkMnFs.ReadByte().ToString() + " - " + GetChecksum(SaveFilePath).ToString());
            UnloadSaveFile();
        }

        /// <summary>
        /// Calculate the value of the Checksum byte for the Generation 1 save files.
        /// </summary>
        /// <param name="SaveFilePath">The Path to the save file.</param>
        /// <returns>A byte containing the checksum result.</returns>
        public static byte GetChecksum(string SaveFilePath)
        {
            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            //Go to the first byte that computes in the checksum.
            PkMnFs.Seek(Gen1Structs.PlayerNameOffset, SeekOrigin.Begin);
            uint ChkSm = 0;

            //Parse each byte from the first byte, to the last one.
            while (PkMnFs.Position < Gen1Structs.ChecksumOffset)
            {
                ChkSm += (uint)PkMnFs.ReadByte();
            }

            //Return the inverse of the resultant byte.
            return (byte)~ChkSm;
        }

        /// <summary>
        /// Loads a Save File. Remember to unload with UnloadSaveFile.
        /// </summary>
        /// <param name="path">The path to the save file.</param>
        public static void LoadSaveFile(string path)
        {
            PkMnFs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
            IsLoaded = true;
        }

        /// <summary>
        /// Unloads a previously loaded save file.
        /// </summary>
        public static void UnloadSaveFile()
        {
            if (IsLoaded == true)
            {
                PkMnFs.Close();
                IsLoaded = false;
            }
        }

        /// <summary>
        /// Get the number of PkMn in the player's party, according to the save file.
        /// </summary>
        /// <param name="SaveFilePath">The path to the save file</param>
        /// <returns>An integer that represent the party length.</returns>
        public static int GetPartyLength(string SaveFilePath)
        {
            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            //Just read and return the value of the first byte in the structure.

            PkMnFs.Seek(Gen1Structs.PokemonListOffset, SeekOrigin.Begin);
            return (int)PkMnFs.ReadByte();
        }

        /// <summary>
        /// Return the number of the current loaded box.
        /// </summary>
        /// <param name="SaveFilePath">The path to the save file</param>
        /// <returns>An integer with the current loaded box index</returns>
        public static int CheckCurrentBoxIndex(string SaveFilePath)
        {
            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            //Just read and return the value of the first byte in the structure, with index 1

            byte[] CurrentBoxArray = BitTools.SplitIntoNibbles(BitTools.ReadByte(Gen1Structs.CurrentBoxOffset, PkMnFs));
            return (CurrentBoxArray[1]+0x01);
        }

        /// <summary>
        /// Return the number of pokemon in a box, acording to the save file. If it fails, it returns 0xFF.
        /// </summary>
        /// <param name="Box">The box. From 1 to 12</param>
        /// <param name="SaveFilePath">The path to the save file</param>
        /// <returns>The integer with the pokemon count for that box</returns>
        public static int PokemonCountInBox(int Box, string SaveFilePath)
        {
            if (Box < 1 || Box > 12)
            return 0xFF;

            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            //Just read and return the value of the first byte in the structure.

            return BitTools.ReadByte(Gen1Structs.Box1Offset + (1122*(Box-1)), PkMnFs);
        }

        /// <summary>
        /// Return the number of Pokemon in the current loaded box, according to the save file.
        /// </summary>
        /// <param name="SaveFilePath">The path to the save file.</param>
        /// <returns>The integer with the pokemon count for the current box</returns>
        public static int PokemonCountInBox(string SaveFilePath)
        {

            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            //Just read and return the value of the first byte in the structure.

            return BitTools.ReadByte(Gen1Structs.CurrentBoxPkmnListOffset, PkMnFs);
        }

        /// <summary>
        /// Returns TRUE, if a Pokedex index is set as seen.
        /// </summary>
        /// <param name="PokedexIndex">The index of the pokemon in the pokedex, from 1 to 151.</param>
        /// <param name="SaveFilePath">The path to the save file.</param>
        /// <returns>Returns TRUE if it has been seen</returns>
        public static bool IsPokemonSeen(int PokedexIndex, string SaveFilePath)
        {
            if (PokedexIndex < 1 || PokedexIndex > 151)
                return false;

           if (!IsLoaded)
           LoadSaveFile(SaveFilePath);

            //Go to the pokedex bytes
            byte[] Pokedex = BitTools.ReadByte(Gen1Structs.PokedexSeenOffset, 19, PkMnFs);

            //Return the value of the selected bit.
            return ((Pokedex[(PokedexIndex-1) >> 3] >> ((PokedexIndex-1) & 7) & 1) == 1);
        }

        /// <summary>
        /// Returns TRUE, if a Pokedex index is set as owned.
        /// </summary>
        /// <param name="PokedexIndex">The index of the pokemon in the pokedex, from 1 to 151.</param>
        /// <param name="SaveFilePath">The path to the save file.</param>
        /// <returns>Returns TRUE if it has been owned</returns>
        public static bool IsPokemonOwned(int PokedexIndex, string SaveFilePath)
        {
            if (PokedexIndex < 1 || PokedexIndex > 151)
                return false;

            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            //Go to the pokedex bytes
            byte[] Pokedex = BitTools.ReadByte(Gen1Structs.PokedexOwnedOffset, 19, PkMnFs);

            //Return the value of the selected bit.
            return ((Pokedex[(PokedexIndex - 1) >> 3] >> ((PokedexIndex - 1) & 7) & 1) == 1);
        }

        /// <summary>
        /// Set a Pokemon in the pokedex as seen, or not seen.
        /// </summary>
        /// <param name="PokedexIndex">The nPokedex ID of the Pokemon, from 1 to 151.</param>
        /// <param name="status">The seen status. Set this to 1 for seen, and 0 for not seen.</param>
        /// <param name="SaveFilePath">The path to the save file.</param>
        /// <returns>Returns TRUE if succeed</returns>
        public static bool SetPokedexSeen(int PokedexIndex, byte status, string SaveFilePath)
        {
            if (PokedexIndex < 1 || PokedexIndex > 151 || status < 0 || status > 1)
                return false;

            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            byte[] Pokedex = BitTools.ReadByte(Gen1Structs.PokedexSeenOffset, 19, PkMnFs);

            //Bitwise OR if it must be set to 1, Bitwise AND if it must be set to 0

            if (status == 1)
                Pokedex[(PokedexIndex - 1) >> 3] |= (byte)(1 << ((PokedexIndex - 1) % 8));
            else
                Pokedex[(PokedexIndex - 1) >> 3] &= (byte)~(1 << ((PokedexIndex - 1) % 8));

            //Write the byte in the save file
            BitTools.WriteByte(Gen1Structs.PokedexSeenOffset, Pokedex, PkMnFs);
            if (!RewriteChecksum(SaveFilePath))
                return false;
            return true;
        }

        /// <summary>
        /// Set a Pokemon in the Pokedex as Owned, or not Owned.
        /// </summary>
        /// <param name="PokedexIndex">The Pokedex ID of the Pokemkon, from 1 to 151</param>
        /// <param name="status">The Owned status. Set this to 1 for Owned, or 0 for not owned.</param>
        /// <param name="SaveFilePath">The path to the save file</param>
        /// <returns>Returns TRUE if succeed</returns>
        public static bool SetPokedexOwn(int PokedexIndex, byte status, string SaveFilePath)
        {
            if (PokedexIndex < 1 || PokedexIndex > 151 || status < 0 || status > 1)
                return false;

            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            byte[] Pokedex = BitTools.ReadByte(Gen1Structs.PokedexOwnedOffset, 19, PkMnFs);
            if (status == 1)
                Pokedex[(PokedexIndex - 1) >> 3] |= (byte)(1 << ((PokedexIndex - 1) % 8));
            else
                Pokedex[(PokedexIndex - 1) >> 3] &= (byte)~(1 << ((PokedexIndex - 1) % 8));

            BitTools.WriteByte(Gen1Structs.PokedexOwnedOffset, Pokedex, PkMnFs);
            if (!RewriteChecksum(SaveFilePath))
                return false;
            return true;
        }

        /// <summary>
        /// Automatically recalculate and write the checksum in the save file.
        /// </summary>
        /// <param name="SaveFilePath">The path to the save file.</param>
        /// <returns>Returns TRUE if succeed</returns>
        public static bool RewriteChecksum(string SaveFilePath)
        {
            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);
            if (!BitTools.WriteByte(Gen1Structs.ChecksumOffset, GetChecksum(SaveFilePath), PkMnFs))
                return false;
            return true;
        }

        /// <summary>
        /// Set the number of PkMn in the player's party. A wrong value might end in glitches.
        /// Returns FALSE if it fails.
        /// </summary>
        /// <param name="Length">The new value.</param>
        /// <param name="SaveFilePath">The path to the save file.</param>
        /// <returns>Returns true if success.</returns>

        public static bool SetPartyLength(byte Length, string SaveFilePath)
        {
            if (Length > 6 || Length < 1)
                return false;

            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            PkMnFs.Seek(Gen1Structs.PokemonListOffset, SeekOrigin.Begin);
            PkMnFs.WriteByte(Length);
            return true;
        }

        /// <summary>
        /// Get the name of the player, and return it in a string.
        /// </summary>
        /// <param name="SaveFilePath">The path to the save file.</param>
        /// <returns>A string with the player's name.</returns>
        public static string GetPlayerName(string SaveFilePath)
        {
            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            byte[] CharName = new byte[8];

            PkMnFs.Seek(Gen1Structs.PlayerNameOffset, SeekOrigin.Begin);

            for (int x = 0; x < CharName.Length; x++)
                CharName[x] = (byte)PkMnFs.ReadByte();

            return Gen1Functions.ConvertTextToString(CharName);
        }

        /// <summary>
        /// Get the length of the party data, in bytes.
        /// </summary>
        /// <param name="partylength">The number of PkMn in the player's party.</param>
        /// <returns>An integer that represent the size, in bytes, of the party.</returns>
        public static int GetPartyByteSize(int partylength)
        {
            return (partylength * (44 + 23) + 2);
        }

        /// <summary>
        /// Loads a list with all the PkMn in the Player's party, and return it in a Gen1Pokemon array.
        /// </summary>
        /// <param name="SaveFilePath">The path to the save file.</param>
        /// <returns>A pokemon array, with the player's party pokemon.</returns>
        public static Gen1Pokemon[] LoadPokemonList(string SaveFilePath)
        {
            Gen1Pokemon[] PokeList = new Gen1Pokemon[Gen1Functions.GetPartyLength(SaveFilePath)];

            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            for (int x = 0; x < PokeList.Length; x++)
            {
                PokeList[x] = new Gen1Pokemon();
                PokeList[x].LoadFromSaveFile(PkMnFs, (byte)(x + 1));
            }

            UnloadSaveFile();

            return PokeList;
        }

        /// <summary>
        /// Change the species in a pokemon in the Player's Party. It doesn't affect to the stats, name, or any attribute,
        /// but affects to the Pokemon sprites.
        /// </summary>
        /// <param name="PartyPosition">The index of the pokemon in the Player's party, from 1 to 6.</param>
        /// <param name="ID">A byte representing the new specie.</param>
        /// <param name="SaveFilePath">The path to the save file.</param>
        public static void ChangePokemon(byte PartyPosition, byte ID, string SaveFilePath)
        {
            int PartyLength = GetPartyLength(SaveFilePath);
            string[] PkMnList = new string[PartyLength];
            byte[] RawPokemonList = new byte[404];

            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            PkMnFs.Seek(Gen1Structs.PokemonListOffset + 1 + PartyPosition, SeekOrigin.Begin);
            PkMnFs.WriteByte(ID);

            PkMnFs.Seek(Gen1Structs.ChecksumOffset, SeekOrigin.Begin);
            PkMnFs.WriteByte(GetChecksum(SaveFilePath)); //Recompute Checksum

            UnloadSaveFile();
        }

        /// <summary>
        /// Switch a pokemon in the player's party, with another one. The previous one will be lost.
        /// </summary>
        /// <param name="PartyPosition">The index of the pokemon to switch in the Player's party, from 1 to 6.</param>
        /// <param name="Pokemon">The Pokemon that will replace the old one.</param>
        /// <param name="SaveFilePath">The path to the save file.</param>
        public static void SwitchPokemon(byte PartyPosition, Gen1Pokemon Pokemon, string SaveFilePath)
        {
            if (PartyPosition < 1 || PartyPosition > 6)
                return;

            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            PkMnFs.Seek(Gen1Structs.PokemonListOffset + PartyPosition, SeekOrigin.Begin);
            PkMnFs.WriteByte(Pokemon.Species);

            PkMnFs.Seek(Gen1Structs.PokemonListOffset + 8 + (44 * (PartyPosition - 1)), SeekOrigin.Begin);
            foreach (byte b in Pokemon.ReturnBytes())
            {
                PkMnFs.WriteByte(b);
            }

            PkMnFs.Seek(0x303C + (11 * (PartyPosition - 1)), SeekOrigin.Begin); //OT Name
            foreach (byte b in Pokemon.OTName)
            {
                PkMnFs.WriteByte(b);
            }

            PkMnFs.Seek(0x307E + (11 * (PartyPosition - 1)), SeekOrigin.Begin); //PkMn Name
            foreach (byte b in Pokemon.PkMnName)
            {
                PkMnFs.WriteByte(b);
            }

            PkMnFs.Seek(Gen1Structs.ChecksumOffset, SeekOrigin.Begin);
            PkMnFs.WriteByte(Gen1Functions.GetChecksum(SaveFilePath));

            UnloadSaveFile();

        }

        /// <summary>
        /// Attempts to load a Pokemon information from a Box. Returns TRUE if succeed. If the selected pokemon slot is empty, it returns FALSE.
        /// </summary>
        /// <param name="box">The box we want to load. From 1 to 12</param>
        /// <param name="pkmnindex">The position of the pokemon we want to load, inside the box. From 1 to 20.</param>
        /// <param name="SaveFilePath">The path to the save file.</param>
        /// <param name="Pokemon">Output parameter that resemble the pokemon in the box.</param>
        /// <returns></returns>
        public static bool LoadPkMnFromBox(int box, int pkmnindex, string SaveFilePath, out Gen1Pokemon Pokemon)
        {
            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            Pokemon = new Gen1Pokemon(); //WARNING: We overwrite any data that were in this class!
            //Pokemon.Species = 0x00;
            //Preliminary checks to make sure every parameter is correct.

            if (box < 1 || box > 12)
                return false; //Invalid box selected.
            if (pkmnindex < 1 || pkmnindex > 20)
                return false; //Invalid Pokemon selected.

            //Check if the choosen box is loaded into memory. If so, we load it from the current box. If not, we just load it from the box.
            byte[] CurrentPCBox = BitTools.SplitIntoNibbles(BitTools.ReadByte(Gen1Structs.CurrentBoxOffset, PkMnFs));

            //Now, we check if the selected pokemon exists in the box (It's not an empty slot in the box).
            if (CurrentPCBox[1] == box - 1)
            {
                if (BitTools.ReadByte(Gen1Structs.CurrentBoxPkmnListOffset, PkMnFs) < pkmnindex)
                    return false; //If you have 13 pkmn in the box, and pkmnindex is 15, it's an empty slot.
            }
            else
                if (BitTools.ReadByte(Gen1Structs.Box1Offset + (33 * (box - 1)), PkMnFs) < pkmnindex)
                    return false;

            //Now that we are finally done with the checks, we load the 33 bytes of the desired pokemon.
            if (CurrentPCBox[1] == box - 1)
            {
                if (!Pokemon.LoadFromPCBytes(BitTools.ReadByte(Gen1Structs.CurrentBoxPkmnListOffset + 22 + (33 * (pkmnindex - 1)), 33, PkMnFs)))
                    return false;
            }
            else
                if (!Pokemon.LoadFromPCBytes(BitTools.ReadByte(Gen1Structs.Box1Offset + (1122 * (box - 1)) + 22 + (33 * (pkmnindex - 1)), 33, PkMnFs)))
                    return false;

            //We succeed, return true.
            return true;

        }

        /// <summary>
        /// Overwrites a Pokemon slot in a PC box.
        /// </summary>
        /// <param name="box">The selected box, from 1 to 12. If it's the current loaded box, it replaces the pokemon in the loaded box.</param>
        /// <param name="pkmnindex">The pokemon slot to replace. It doesn't check if it's empty or not, be aware!</param>
        /// <param name="SaveFilePath">The path to the save file.</param>
        /// <param name="Pokemon">The pokemon that will take place.</param>
        /// <returns>Returns TRUE if succe</returns>
        public static bool WritePokemonInPc(int box, int pkmnindex, string SaveFilePath, Gen1Pokemon Pokemon)
        {
            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            if (box < 1 || box > 12)
                return false;

            byte[] CurrentPCBox = BitTools.SplitIntoNibbles(BitTools.ReadByte(Gen1Structs.CurrentBoxOffset, PkMnFs));

            if (CurrentPCBox[1] == box - 1)
            {
                if (!BitTools.WriteByte(Gen1Structs.CurrentBoxPkmnListOffset + (pkmnindex), Pokemon.Species, PkMnFs))
                    return false;
                if (!BitTools.WriteByte(Gen1Structs.CurrentBoxPkmnListOffset + 22 + (33 * (pkmnindex - 1)), Pokemon.ReturnPCBytes(), PkMnFs))
                    return false;
                if (!BitTools.WriteByte(Gen1Structs.CurrentBoxPkmnListOffset + 682 + ((pkmnindex - 1) * 11), Pokemon.OTName, PkMnFs))
                    return false;
                if (!BitTools.WriteByte(Gen1Structs.CurrentBoxPkmnListOffset + 902 + ((pkmnindex - 1) * 11), Pokemon.PkMnName, PkMnFs))
                    return false;
            }
            else
            {
                if (!BitTools.WriteByte(Gen1Structs.Box1Offset + (1122 * (box - 1)) + (pkmnindex), Pokemon.ReturnPCBytes(), PkMnFs))
                    return false;
                if (!BitTools.WriteByte(Gen1Structs.Box1Offset + (1122 * (box - 1)) + 22 + (33 * (pkmnindex - 1)), Pokemon.ReturnPCBytes(), PkMnFs))
                    return false;
                if (!BitTools.WriteByte(Gen1Structs.Box1Offset + (1122 * (box - 1)) + 682 + ((pkmnindex - 1) * 11), Pokemon.OTName, PkMnFs))
                    return false;
                if (!BitTools.WriteByte(Gen1Structs.Box1Offset + (1122 * (box - 1)) + 902 + ((pkmnindex - 1) * 11), Pokemon.PkMnName, PkMnFs))
                    return false;
            }

            BitTools.WriteByte(Gen1Structs.ChecksumOffset, GetChecksum(SaveFilePath), PkMnFs);
            return true;
        }

        

        /// <summary>
        /// Convert a String to a sucession of bytes according to the PkMn Alphabet. It adds a 0x50 automatically at the end.
        /// </summary>
        /// <param name="str">The string to be converted.</param>
        /// <returns>An array of bytes, that represent PkMn alphabet chars.</returns>
        public static byte[] ConvertStringToText(string str)
        {
            int cnt = 0; byte[] swap; byte[] res = new byte[1] { 0x50 };
            foreach (char c in str.ToCharArray())
            {
                for (int x = 0; x < Gen1Structs.GenIAlph.Length; x++) //x is the value we're looking for. The index of our character in the alphabet.
                {
                    if (c.ToString() == Gen1Structs.GenIAlph[x])
                    {
                        //If our counter is greater than the size of our array, we resize it
                        //using the swap array, and redefining our array.
                        //IMPORTANT: array.Length returns the size in items (from 1 to n). When using indexes, the index start at 0 (from 0 to n).
                        //So, the last index of an array, is always the Size minus 1 (array.Length - 1).
                        if (cnt > res.Length - 1)
                        {
                            swap = res;
                            res = new byte[cnt + 1];
                            for (int n = 0; n < swap.Length; n++)
                            {
                                res[n] = swap[n];
                            }
                        }
                        res[cnt] = (byte)(x + 0x80); //We convert our byte to a valid PkMn Alphabet byte
                        cnt++;
                    }
                }
            }
            //One more resize, we need to input the terminator 0x50.
            swap = res;
            res = new byte[res.Length + 1];
            for (int n = 0; n < swap.Length; n++)
            {
                res[n] = swap[n];
            }

            res[res.Length - 1] = 0x50;

            return res;
        }

        /// <summary>
        /// Manually counts the number of PkMn in the Player's party. Usefull for debugging.
        /// </summary>
        /// <param name="SaveFilePath">The path to the save file.</param>
        /// <returns>A byte that represents the number of pokemon in the party.</returns>
        public static byte CountPkMnInParty(string SaveFilePath)
        {
            byte result = 0x00;
            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            PkMnFs.Seek(Gen1Structs.PokemonListOffset + 0x01, SeekOrigin.Begin);
            while (PkMnFs.ReadByte() != 0xFF || result < 0x06)
                result++;
            return result;
        }

        /// <summary>
        /// Set the player's money
        /// </summary>
        /// <param name="amount">The new money value</param>
        /// <param name="SaveFilePath">The path to the save file</param>
        /// <returns>Returns TRUE if success.</returns>
        public static bool SetMoney(int amount, string SaveFilePath)
        {
            //We can have up to 999,999 total money.
            if (amount < 0 || amount > 999999)
                return false;

            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            char[] aval_ = amount.ToString().ToCharArray();
            byte[] values = new byte[6], defvalues = new byte[3];

            //We convert the value to a char array. If it doesn't have 6 indexes, we add more.
            if(aval_.Length < 6){

                char[] swap = aval_;
                aval_ = new char[6]; //Now we will have a 6 byte array.

                for (int n = 0; n < 6 - swap.Length; n++)
                    aval_[n] = '0'; //Fill the array with 0

                //Merge the swap array with the value array

                for (int n = 6 - swap.Length; n < 6; n++)
                    aval_[n] = swap[n - (6 - swap.Length)];
            }

            //Convert each number to a byte.
            for (int x = 0; x < 6; x++)
                values[x] = Convert.ToByte(aval_[x].ToString(), 10);

            //Now, merge each 2 bytes into a single byte in big endian format
            for (int x = 0; x < 6; x += 2)
                defvalues[x] = (byte)((values[x] << 4) & values[x + 1]);

            //And, finally, store them in the memory
                if (!BitTools.WriteByte(Gen1Structs.MoneyOffset, defvalues, PkMnFs))
                    return false;
            return true;
        }

        /// <summary>
        /// Get the player's money
        /// </summary>
        /// <param name="SaveFilePath">The path to the save file</param>
        /// <returns>A 32 signed integer with the value of the money</returns>
        public static int GetMoney(string SaveFilePath)
        {
            if (!IsLoaded)
                LoadSaveFile(SaveFilePath);

            byte[] values = new byte[6], defvalues;
            int cnt = 0;
            string res = "";

            //Get the money in BCD
            defvalues = BitTools.ReadByte(Gen1Structs.MoneyOffset, 3, PkMnFs);

            //Get each BCD value in a byte so we can handle it easier
            for (int x = 0; x < 3; x++){
                values[cnt] = (byte)((defvalues[x]>>4) & 0x0f);
                values[cnt+1] = (byte)(defvalues[x] & 0x0f);
                    cnt += 2; //Secondary counter
            }

            //Pass each number to a string. Instead of calculate the value, we make a text with it.
            foreach (byte b in values)
                res += b.ToString();

            //Convert the string into an integer and return it.
            return Convert.ToInt32(res);
        }
    }
}